#!/usr/bin/env python
# coding=utf-8

import MySQLdb,sys,os,time,re,string,traceback
import ConfigParser
from decimal import *
currpath=sys.path[0]
root_path=currpath[:currpath.find('src')]
sys.path.append(root_path+'src')
sys.path.append(root_path+'src/tools')
sys.path.append(root_path+'src/tools/sphinx')
sys.path.append(root_path+'src/tools/memcached')
from sphinxapi import *
from memcache import *
from enities import *
import setting

IS_DEBUG=False
#IS_DEBUG=True

MC_DEST_KEY01='py_route01_{ID}'
MC_DEST_KEY02='py_route02_{OID}'
mc = Client([setting.server_memcached], debug=0)
'''
    数据库配置信息
'''
    
mode = SPH_MATCH_ALL
host = setting.server_sphinx

class Analyzer:
    
    
    def __init__(self,_title='',_descr='',_article=''):
        self.conn=MySQLdb.Connection(setting.server_vacation,setting.username_vacation,setting.password_vacation,setting.database_vacationdb,use_unicode=False,charset='utf8')
        
        self.title=_title
        self.descr=_descr
        self.article=_article
    
    '''
        #通过sphinx切词
    '''
    def cutWords(self,text,index,port):
        targets=[]    #目标词
        cl = SphinxClient()
        cl.SetServer(host,port)
        cl.SetWeights([100, 1])
        cl.SetMatchMode(mode)
        res = cl.Query(text,index)
        if not res:
            print 'query failed: %s' % cl.GetLastError()
            return targets
        if res.has_key('words'):
            for info in res['words']:
                targets.append(info['word'])
                #print '\t\'%s\' found %d times in %d documents' % (info['word'], info['hits'], info['docs'])
        return targets
    
    '''
        #通过数据库查询切词
    '''
    def cutWords02(self,sql):
        targets=[]    #目标词
        try:
            curs=self.conn.cursor()
            curs.execute(sql)
            m=curs.fetchall()
            for i in m:
                targets.append(i[0])
        except:
            print traceback.format_exc(sys.exc_info())
        finally:
            curs.close()
        return targets
    
    '''
        #获取备选景点词
    '''
    def getDests(self,words):
        dests={}    #目标词
        cl = SphinxClient()
        cl.SetServer(host,9314)
        cl.SetWeights([1000, 1])
        cl.SetMatchMode(mode)
        for q in words:
            res = cl.Query('^#$'.replace('#',q),'dest_index_cut')
            if res.has_key('matches'):
                n = 1
                #print 'Matches:<'+q+'>'+str(res['matches'])
                if res['matches'] and len(res['matches'])>0:
                    if not dests.has_key(q):
                        dests[q]={}
                else:
                    continue
                
                for match in res['matches']:
                    attrsdump = ''
                    for attr in res['attrs']:
                        attrname = attr[0]
                        attrtype = attr[1]
                        value = match['attrs'][attrname]
                        if attrtype==SPH_ATTR_TIMESTAMP:
                            value = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(value))
                        attrsdump = '%s, %s=%s' % (attrsdump,attrname,value)
                        #d=mc.get(MC_DEST_KEY01.replace('{OID}',str(match['id'])))
                        d=self.getDestEntity(str(match['id']), MC_DEST_KEY01.replace('{ID}',str(match['id'])))
                        if d and (q==d.dest or q==d.alias01 or q==d.alias02 or q==d.alias03):
                            dests[q][match['id']]=d
                    #print '%d. doc_id=%s, weight=%d%s' % (n, match['id'], match['weight'], attrsdump)
                    n += 1
        
        iter=dests.keys()
        for it in iter:
            if len(dests[it])==0:
                dests.pop(it)
        return dests
    

    '''
        #对比语料库校验关键词匹配
    '''
    def checkDest(self,_dest,_max=5):
        flag=False
        curs=self.conn.cursor()
        try:
            params=(_dest,_max)
            curs.callproc('PROC_OYESGO_VACATIONS_ANALYSE_CHECKDEST',params)
            m=curs.fetchall()
            flag=(m[0][0]=='true')
        except:
            print traceback.format_exc(sys.exc_info())
        finally:
            curs.close()
        return flag
    
    
    '''
        #剔除预处理文本中的修饰性景点
    '''
    def removeWrongDest(self,title,describe,articles):
        result=[]
        result.append(self.replWrongDest(title))
        result.append(self.replWrongDest(describe))
        articles02=[]
        for a in articles:
            articles02.append(self.replWrongDest(a))
        result.append(articles02)
        return result

    def replWrongDest(self,text):
        dests = self.cutWords(text, 'dest_index_cut', 9314)
        adjectives = self.cutWords02("SELECT words FROM analysis_dict_cut WHERE '"+text+"'REGEXP words ORDER BY weight DESC")
        for adj in adjectives:
            for dest in dests:
                if text.find(adj+dest)>-1:
                    if self.checkDest(adj+dest,1):
                        text=text.replace(adj+dest,'')
                        #print '##############################replaced: '+adj+dest
                    
        return text
        
        
        
    '''
        #1st 文本预处理（一级关键字提取）
    '''
    def preprocess(self,depcity,title,describe,articles):
        result=self.removeWrongDest(title,describe,articles)
        title=result[0]
        describe=result[1]
        articles=result[2]
        maxlentgh=0
        dests = {}
        d_titles = self.getDests(self.cutWords(title, 'dest_index_cut', 9314))
        for k in d_titles:
            dests[k]=d_titles[k]
            for k1 in d_titles[k].keys():
                if maxlentgh < d_titles[k][k1].length:
                    maxlentgh=d_titles[k][k1].length
        d_describe = self.getDests(self.cutWords(describe, 'dest_index_cut', 9314))
        for k in d_describe:
            dests[k]=d_describe[k]
            for k1 in d_describe[k].keys():
                if maxlentgh < d_describe[k][k1].length:
                    maxlentgh=d_describe[k][k1].length
        d_planes=[]
        for a in articles:
            d_article = self.getDests(self.cutWords(a, 'dest_index_cut', 9314))
            d_planes.append(d_article)
            for k in d_article:
                dests[k]=d_article[k]
                for k1 in d_article[k].keys():
                    if maxlentgh < d_article[k][k1].length:
                        maxlentgh=d_article[k][k1].length
        iter=dests.keys()
        for it in iter:
            freq_re=re.compile(it,re.X|re.S)
            '''在标题中词频'''
            f_titles=freq_re.findall(title)
            freq_t = Decimal(f_titles and len(f_titles) or 0)
            '''在描述中词频'''
            f_descs=freq_re.findall(describe)
            freq_d = Decimal(f_descs and len(f_descs) or 0)
            '''在正文词频'''
            f_arts=freq_re.findall(''.join(articles))
            freq_a = Decimal(f_arts and len(f_arts) or 0)
            '''在全文总词频'''
            freq_total=freq_t + freq_d + freq_a
            for k in dests[it].keys():
                dests[it][k].setWP(Decimal(maxlentgh),freq_total,(freq_t,freq_d,freq_a))
        return dests

    '''
        #2nd 关键字筛选（相关目的地提取、均衡各项权重因子）
    '''
    def fliter(self,dests):
        total_weight=0.0
        dests_2nd={}
        for k1 in dests.keys():
            for k2 in dests[k1].keys():
                fullpath = dests[k1][k2].full
                fp=''
                for p in fullpath.split('/'):
                    fp=fp+p+'/'
                    if len(fp.split('/'))==2:
                        #计算总权值
                        total_weight+=dests[k1][k2].weight
                    if dests_2nd.has_key(fp):
                        dests_2nd[fp] = dests_2nd[fp] + dests[k1][k2].weight
                    else:
                        dests_2nd[fp]=dests[k1][k2].weight
                    #if IS_DEBUG:
                    #    print dests[k1][k2].prepath+'/'+dests[k1][k2].dest+'\t'+fp+'\t'+str(dests[k1][k2].weight) +'\t'+ str(len(fp.split('/')))
        #'''
        if IS_DEBUG:
            for it in dests.keys():
                print '\n'+it+': '
                for k in dests[it].keys():
                    print '\t'+dests[it][k].full+'\t'+dests[it][k].prepath+'/'+dests[it][k].dest+'\t'+str(dests[it][k].len)+'\t'+str(dests[it][k].freq)+'\t'+str(dests[it][k].adds)+'\t'+str(dests[it][k].weight)
        #'''

        return (total_weight,dests_2nd)
    
    '''
        #解析
    '''
    def analyzer(self,depcity,url,title,describe,articles):
        if title is None:
            title=''
        if describe is None:
            describe=''
        if articles is None:
            articles=['']
        #线路类型：出境/国内/周边，配置图片，途径景点，途径景区
        response={'type':'',
                  'pic':'no_photo.jpg',
                  'go_t':'-',
                  'back_t':'-',
                  '':'',
                  'sights':'',
                  'dests':''}
        dests = self.preprocess(depcity,title,describe,articles)
        result = self.fliter(dests)
        dests_1st=result[1]
        dests_2nd={}
        list_tmp=dests_1st.items()
        b = sorted(list_tmp,cmp=lambda x,y:cmp(len(x[0].split('/')),len(y[0].split('/'))) or cmp(x[1],y[1]))
        #print '#first filter：----------------------------------'
        for k in b:
            pre_weight=100.0000
            count=len(k[0])/4 - 1
            for i in range(count):
                tmp=k[0][0:5+4*i]
                pre_weight += dests_1st[tmp]*len(tmp.split('/'))
                #if IS_DEBUG:
                #    print tmp+'\t'+str(dests_2nd[tmp])
            #print MC_DEST_KEY02.replace('{ID}',str(k[0][1:].replace('/','')))
            #d=mc.get(MC_DEST_KEY02.replace('{ID}',str(k[0][1:].replace('/',''))))
            d=self.getDestEntity(str(k[0][1:].replace('/','')), MC_DEST_KEY02.replace('{OID}',str(k[0][1:].replace('/',''))))
            if IS_DEBUG:
               print k[0] +'\t'+'\t'+d.prepath+'/'+d.dest+'\t'+str(k[1])+'\t'+str((k[1]*100)/result[0])+'\t'+str(k[1]*pre_weight/result[0])
            dests_2nd[k[0]] = k[1]*pre_weight/result[0]
            
        #print '\n#second filter：----------------------------------'
        pass_key=''
        stop_key=['-']
        #按级别由低到高、权值由高到低分类排序
        list_tmp=dests_2nd.items()
        b = sorted(list_tmp,cmp=lambda x,y:cmp(len(x[0].split('/')),len(y[0].split('/'))) or cmp(y[1],x[1]))
        stop=False
        count=0
        #计算出现洲的总数
        content_num=0
        #计算出现国家的总数
        country_num=0
        for k in b:
            if re.compile(r'\^[0-9]*/$',re.X|re.S).search(k[0]):
                content_num+=1
            if re.compile(r'\^[0-9]*/[0-9]*/$',re.X|re.S).search(k[0]):
                country_num+=1
        for k in b:
            #d=mc.get(MC_DEST_KEY02.replace('{ID}',str(k[0][1:].replace('/',''))))
            d=self.getDestEntity(str(k[0][1:].replace('/','')), MC_DEST_KEY02.replace('{OID}',str(k[0][1:].replace('/',''))))
            #print k[0] +'\t'+'\t'+d.prepath+'/'+d.dest+'\t'+str(k[1])
            if stop==False:
                #洲\国家\国内级别扩展到省市一级
                if re.compile(r'\^[0-9]*/$',re.X|re.S).search(k[0]):
                    #if len(pass_key)==0:
                    #    pass_key=k[0]
                    #else:
                    #print str(k[0])+'\t'+str(k[1])+'\t'+str(content_num)
                    if k[1]<(round(100)/content_num):
                        stop_key.append(k[0])
                if re.compile(r'\^[0-9]*/[0-9]*/$',re.X|re.S).search(k[0]):
                    count+=1
                    if len(pass_key)==0:
                        if '^001/001/'==k[0] and count==1:
                            pass_key=k[0]
                        elif '^001/001/'==k[0]:
                            stop_key.append(k[0])
                            #stop=True
                    #print str(k[0])+'\t'+str(k[1])+'\t'+str(country_num)
                    if count>1 and k[1]<(round(100)/country_num):
                        stop_key.append(k[0])
                    else:
                        if country_num>9 and k[1]<(round(10*country_num)/(country_num)):
                            stop_key.append(k[0])
                            
                        
                if len(pass_key)==9 and re.compile(r'\^001/001/[0-9]',re.X|re.S).search(k[0]):
                    pass_key=k[0]
                    #stop=True
        if IS_DEBUG:            
            print 'All dests must include `'+pass_key+'`.'
            print 'All dests must unclude `'+''.join(stop_key)+'`.'
        
        #print '\n#third filter：----------------------------------'
        dests_ed={}
        for it in dests.keys():
            d_tmp=None
            for v in dests[it].values():
                #print v.full+'\t'+v.prepath+'/'+v.dest+'\t'+str(dests_2nd[v.full+'/'])
                v.right=False
                v.t_weight=round(dests_2nd[v.full+'/'],5)
                dests_ed[v.id]=v
                if d_tmp is None:
                    d_tmp=v
                elif dests_2nd[d_tmp.full+'/']<dests_2nd[v.full+'/']:
                    d_tmp=v
            passed=True
            for s in stop_key:
                if (d_tmp.full+'/').find(s)>-1:
                    passed=False
            if (passed
                and ((d_tmp.full+'/').find(pass_key)>-1 or pass_key.find(d_tmp.full)>-1)):
                d_tmp.right=True
                dests_ed[d_tmp.id]=d_tmp
        
        
        #print '\n#show filter result:------------------------------\n'
        level_tmp=0
        mostdetailed_pic='no_photo.jpg'      #最详细的正确景点图片
        list_tmp=dests_ed.items()
        bs = sorted(list_tmp,cmp=lambda x,y:cmp(len(x[0]),len(y[0])) or cmp(y[1].t_weight,x[1].t_weight))
        for b in bs:
            d_tmp=b[1]
            if d_tmp.right and level_tmp<len(d_tmp.id) and d_tmp.pic!='no_photo.jpg' and d_tmp.pic.find('.jpg')>0:
                level_tmp=len(d_tmp.id)
                mostdetailed_pic=d_tmp.id[:-3]+'/'+d_tmp.pic
            if d_tmp.right and len(d_tmp.id)>3:
                response['sights'] += d_tmp.prepath+'/'+d_tmp.dest+','
                response['dests'] += d_tmp.dest+','
            if IS_DEBUG:
                print d_tmp.full+'\t'+d_tmp.prepath+'/'+d_tmp.dest+'\t'+d_tmp.id+'\t'+str(d_tmp.t_weight)+'\t'+str(d_tmp.right)
        
        #线路类型
        response['type']=self.getLineType(depcity,title+'-'+describe,pass_key)
        #线路目的地标识图片
        response['pic']=mostdetailed_pic
        #交通工具
        traffic=self.getTraffic(title,response['type'])
        response['go_t']=traffic[0]
        response['back_t']=traffic[1]
        response['dests']=response['dests'].replace(depcity,'')
        response['sights']=response['sights'].replace(depcity,'')
        #tesssssssssssssssssssssssssssssssst
        #for i in response.keys():
        #    print i +': '+response[i]
        self.log_main(depcity,url,title,describe,''.join(articles),response['sights'],response['dests'])
        self.log_sub(url,bs)
        return response

    '''
        #判断线路类型（邮轮/出境/周边/国内）
    '''
    def getLineType(self,depcity,text,passkey):
        linetype='国内'
        if text.find('邮轮')>-1 or text.find('游轮')>-1:
            linetype='邮轮'
        elif passkey.find('^001/001/')<0:
            linetype='出境'
        else:
            #先判断是否周边游
            curs=self.conn.cursor()
            try:
                curs.execute('SELECT COUNT(id) FROM round_dest WHERE city=\''+depcity+'\' AND around_city=\''+re.sub(r'[^0-9]*',passkey,'')+'\'')
                ls=curs.fetchall()
                if ls[0][0]>0:
                    linetype='周边'
            except:
                print traceback.format_exc(sys.exc_info())
            finally:
                curs.close()
        return linetype
    
    '''
        #判断交通工具（暂未作细分，待改进）
    '''
    def getTraffic(self,title,linetype):
        traffic=('-','-')
        if linetype=='出境' or title.find('双飞')>-1:
            traffic=('飞机','飞机')
        elif linetype=='邮轮':
            traffic=('邮轮','邮轮')
        elif title.find('双卧')>-1 or title.find('三卧')>-1:
            traffic=('卧铺','卧铺')
        elif linetype=='周边':
            traffic=('汽车','汽车')
        return traffic
            
    '''
        #保存分析主数据
    '''
    def log_main(self,depcity,url,title,describe,articles,sights,dests):
        try:
            curs=self.conn.cursor()
            params=(depcity,url,title,describe,articles,sights,dests)
            curs.callproc('PROC_OYESGO_VACATIONS_ANALYSE_MAIN',params)
        except:
            print traceback.format_exc(sys.exc_info())
        finally:
            curs.close()
            
    '''
        #保存数据详细子项
    '''
    def log_sub(self,url,bs):
        try: 
            curs=self.conn.cursor()
            _results=''
            _match=''
            _len=''
            _freq=''
            _adds=''
            _weight=''
            _t_weight=''
            for d in bs:
                _results=_results+'#_#'+d[1].prepath+'/'+d[1].dest;
                _len=_len+'#_#'+str(d[1].len);
                _match=_match+'#_#'+str(d[1].right);
                _freq=_freq+'#_#'+str(d[1].freq);
                _adds=_adds+'#_#'+str(d[1].adds);
                _weight=_weight+'#_#'+str(d[1].weight);
                _t_weight=_t_weight+'#_#'+str(d[1].t_weight);
            params=(len(bs),
                url,
                _results[3:],
                _match[3:],
                _len[3:],
                _freq[3:],
                _adds[3:],
                _weight[3:],
                _t_weight[3:])
            curs.callproc('PROC_OYESGO_VACATIONS_ANALYSE_SUB',params)
        except:
            print traceback.format_exc(sys.exc_info())
        finally:
            curs.close()
    
    '''
        #获取dest对象
    '''
    def getDestEntity(self,id,key):
        dest=mc.get(key)
        if dest is None:
            sql='SELECT oid,id,destination,prepath,IF(alias01 IS NULL,\'\',alias01),IF(alias02 IS NULL,\'\',alias02),IF(alias03 IS NULL,\'\',alias03),img FROM destination WHERE id>0'
            if key.find('py_route01_')>-1:
                sql+=' AND id='+str(id)+''
            elif key.find('py_route02_')>-1:
                sql+=' AND oid=\''+str(id)+'\''
            else:
                sql+=' AND id=\'\''
            curs=self.conn.cursor()
            try:
                curs.execute(sql)
                ls = curs.fetchall()
                for r in ls:
                    dest=Dest(r[0],r[1],r[2],r[3],r[4],r[5],r[6])
                    dest.pic=r[7]
                    mc.set(MC_DEST_KEY01.replace('{ID}',str(dest.id)), dest)
                    mc.set(MC_DEST_KEY02.replace('{OID}',str(dest.oid)), dest)
            except:
                print traceback.format_exc(sys.exc_info())
            finally:
                curs.close()
        return dest
            
    '''
    '''
    def __del__(self):
        self.conn.close()
        
'''
    #初始化cache
'''
def initCached():
    conn=MySQLdb.Connection(setting.server_vacation,setting.username_vacation,setting.password_vacation,setting.database_vacationdb,use_unicode=False,charset='utf8')
    try:
        curs=conn.cursor()
        try:
            curs.execute('SELECT oid,id,destination,prepath,IF(alias01 IS NULL,\'\',alias01),IF(alias02 IS NULL,\'\',alias02),IF(alias03 IS NULL,\'\',alias03),img FROM destination WHERE oid<>\'000\'')
            ls = curs.fetchall()
            for r in ls:
                dest=Dest(r[0],r[1],r[2],r[3],r[4],r[5],r[6])
                dest.pic=r[7]
                mc.set(MC_DEST_KEY01.replace('{ID}',str(dest.id)), dest)
                mc.set(MC_DEST_KEY02.replace('{OID}',str(dest.oid)), dest)
                print dest.id+'\t'+dest.full+'\t'+dest.prepath+'\t'+dest.dest
                
        except:
            print traceback.format_exc(sys.exc_info())
        finally:
            curs.close()
        print 'init cached finished!'
    finally:
        conn.close()
        
def test():
    conn=MySQLdb.Connection(setting.server_vacation,setting.username_vacation,setting.password_vacation,setting.database_vacationdb,use_unicode=False,charset='utf8')
    try:
        curs=conn.cursor()
        try:
            #url='http://www.utourworld.com/InternationLine/ShowLineDetail.aspx?lineid=710JOVH49I'
            url='http://www.ctsgz.cn/tpl/index/display_line_detail_web.do;jsessionid=D6E1EFDD51AED4A28C84CEA0A9F859B5?bh=20090803151832'
            url='http://www.toworldtravel.com/TouristGroup/viewLine/id_1283/startcity_1'
            curs.execute('SELECT id,depart_city,route_url,route_title,CONCAT(IF(sights is null,\'\',sights),IF(details is null,\'\',details)),travel_plan FROM route where image_url like \'0/%\' limit 0,50')
            #curs.execute('SELECT id,depart_city,route_url,route_title,CONCAT(IF(sights is null,\'\',sights),IF(details is null,\'\',details)),travel_plan FROM route where update_time<\'2010-08-07\'')
            #curs.execute('SELECT id,depart_city,route_url,route_title,CONCAT(IF(sights is null,\'\',sights),IF(details is null,\'\',details)),travel_plan FROM route where sights = \'/欧洲,\'  order by update_time desc')
            ls = curs.fetchall()
            for i in ls:
                analyzer=Analyzer()
                plans=[]
                try:
                    curs.execute('SELECT brief FROM schedule where routeId='+str(i[0])+'')
                    ls_sc = curs.fetchall()
                    for j in ls_sc:
                        plans.append(j[0])
                except:
                    pass
                route=analyzer.analyzer(i[1], i[2], i[3], i[5], plans)
                curs.execute('UPDATE route SET sights=\''+route['sights']+'\',destination=\''+route['dests']+'\',image_url=\''+route['pic']+'\' WHERE id='+str(i[0]))
                conn.commit()
                print route['pic']
        except:
            print traceback.format_exc(sys.exc_info())
        finally:
            curs.close()
    finally:
        conn.close()
                
if __name__ == '__main__':
    #initCached()
    test()
    '''
    a=Analyzer()
    #a.log_main('depcity','url','title','describe','articles','sights','dests')
    plans=('自行前往机场办理登机手续，乘机抵达美丽椰城——海口，在椰风海韵中观市容市貌，入住酒店。',
               '早餐后(8点左右出发)乘车前往博鳌,车程约100分钟，途中车览万泉河风光，游【万泉河竹筏漂流】（游览时间约30分钟）外观博鳌水城，之后自费乘船游览被誉为世界上最完美的江河入海口处、被记入吉尼斯世界记录的【博鳌玉带滩】（含乘船往返及滩上游玩累计时间约90分钟），从博鳌前往兴隆，车程约90分钟，参观具有科研、观光和植物种植保护功能的【兴隆热带植物园】（游览时间约40分钟），晚上可自费欣赏泰国特色的红艺人表演（150元/人自理。时间约120分钟）',
               '早餐后（07:30左右出发）乘车赴三亚，、之后车程约90分钟后自费游览海南特有的【槟榔园蚩尤部落】（自理168元/人、游览时间2.5小时左右），用午餐后，车程约40分钟漫步“天下第一湾”【亚龙湾沙滩】，（游览时间约30分钟）这里沙滩宽阔、沙粒洁白细软、海水清澈，蓝天、白云相互映衬、任您流连忘返。之后约20分钟抵达【大（小）东海旅游中心潜水基地】（约120分钟）旅游区感受大海魅力（可自费参加各种海洋项目，如水肺潜水等）。车览三亚湾情侣路—【椰梦长廊】。约30分钟后游著名胜地【天涯海角、南天一柱】（游览时间约120分钟），整个景区如诗如画。晚餐可自费享用海鲜风味大餐，不参与的客人食用团队餐（150元/人自理，用餐时间约120分钟）。',
               '早餐后（07:30左右出发）,40分钟左右后自费游览集中外园林、佛教文化于一体的福泽之地的【南山佛教文化苑风景区】（自理198元/人含素斋和电瓶车）（游览时间约150分钟），这里能让您闻到清新的空气、听到寺的钟声、在千年古刹感受鸟语花香、享受独特的佛教文化氛围，观108米南山海上三面观音风采。午餐后，车程约50分钟到达乘船码头，乘船时间约30分钟，游览中国的马尔代夫—【蜈支洲岛】（含船票）它是世界上为数不多的惟一没有礁石或者鹅卵石混杂的海岛。（游览时间约150的分钟）。前往亚洲唯一的岛屿型猕猴自然保护区-南湾猴岛天朗度假酒店入住，您在这里推开窗即可呼吸大海的气息，听海浪声声，距离沙滩仅仅20余米，您可休闲漫步，沙滩踏浪，玩排球，海滩捉蟹，拉网捕鱼——尽享快乐与惬意!',
               '早餐后（07:30左右出发）,自费游览海中猴王的神圣之地（车程40分钟左右）---【南湾猴岛】（自理123元/人、游览时间2.5小时），途中用午餐，之后前往素有“南天斗宿、洞天福地、东山耸翠"之称的海南第一山----【文笔峰】（赠送项目）。在文笔峰用养生素斋后返回海口，车程约60分钟。结束旅程，返回您温馨的家。')
    
    dests=a.analyzer('北京',
                     'http://www.test.com/',
                     '中国武夷山双卧5日给您最充足的时间，感受最全面的武夷山',
                     '北京,武夷山,天游峰,晒布岩,云窝,茶洞,仙浴潭,接笋峰,九曲溪,曲溪,漂流,武夷宫,仿宋古街,瀑布,观音瀑,清新,于山,天成禅院,宾曦洞,语儿泉,集云关,一线天,风洞,★ 坐在竹筏之上尽情欣赏九曲两岸武夷“碧水丹山”之绝妙佳景；★ 奇特的自然地貌，神秘的道教文化，自然和人文的绝佳组合；★ 龙川大峡谷加上武夷山经典三大景区；',
                     plans)
    '''
